from __future__ import annotations

from testfixtures import compare

import pytermgui
from pytermgui import Color, DensePixelMatrix, str_to_color, tim
from pytermgui.term import Recorder, Terminal, terminal

try:
    from ._exporter_targets import HTML_TARGET, SVG_TARGET
except ImportError:
    from _exporter_targets import HTML_TARGET, SVG_TARGET

MATRIX = [
    [
        "142",
        "96",
        "139",
        "32",
        "179",
        "191",
        "214",
        "127",
        "211",
        "25",
        "93",
        "61",
        "60",
        "103",
        "109",
        "150",
        "36",
        "165",
        "188",
        "103",
        "55",
        "167",
        "212",
        "52",
        "151",
        "114",
        "213",
        "65",
        "58",
        "101",
    ],
    [
        "222",
        "82",
        "143",
        "199",
        "221",
        "70",
        "53",
        "49",
        "122",
        "35",
        "69",
        "162",
        "167",
        "146",
        "114",
        "213",
        "185",
        "167",
        "118",
        "62",
        "196",
        "170",
        "38",
        "204",
        "92",
        "47",
        "217",
        "21",
        "51",
        "167",
    ],
    [
        "178",
        "83",
        "168",
        "211",
        "18",
        "95",
        "222",
        "52",
        "205",
        "172",
        "82",
        "147",
        "181",
        "162",
        "89",
        "226",
        "136",
        "92",
        "30",
        "84",
        "66",
        "183",
        "229",
        "100",
        "160",
        "82",
        "218",
        "223",
        "32",
        "153",
    ],
    [
        "174",
        "196",
        "59",
        "148",
        "130",
        "126",
        "27",
        "51",
        "180",
        "47",
        "142",
        "54",
        "104",
        "63",
        "21",
        "87",
        "113",
        "186",
        "146",
        "212",
        "69",
        "134",
        "157",
        "116",
        "226",
        "63",
        "198",
        "231",
        "219",
        "199",
    ],
    [
        "178",
        "65",
        "39",
        "188",
        "226",
        "75",
        "159",
        "42",
        "143",
        "154",
        "228",
        "179",
        "104",
        "85",
        "128",
        "48",
        "195",
        "183",
        "43",
        "22",
        "191",
        "55",
        "190",
        "86",
        "31",
        "139",
        "228",
        "55",
        "117",
        "182",
    ],
    [
        "47",
        "44",
        "18",
        "45",
        "188",
        "49",
        "33",
        "52",
        "123",
        "211",
        "84",
        "210",
        "159",
        "195",
        "215",
        "174",
        "206",
        "219",
        "208",
        "17",
        "221",
        "167",
        "94",
        "159",
        "21",
        "175",
        "226",
        "149",
        "160",
        "179",
    ],
    [
        "110",
        "53",
        "120",
        "139",
        "129",
        "122",
        "189",
        "72",
        "205",
        "150",
        "149",
        "199",
        "44",
        "60",
        "85",
        "33",
        "145",
        "207",
        "37",
        "88",
        "53",
        "70",
        "139",
        "115",
        "208",
        "185",
        "80",
        "161",
        "142",
        "45",
    ],
    [
        "18",
        "221",
        "85",
        "55",
        "126",
        "210",
        "23",
        "142",
        "59",
        "228",
        "49",
        "128",
        "57",
        "81",
        "79",
        "120",
        "231",
        "112",
        "37",
        "123",
        "218",
        "23",
        "138",
        "169",
        "89",
        "86",
        "35",
        "193",
        "184",
        "126",
    ],
    [
        "198",
        "154",
        "157",
        "129",
        "199",
        "71",
        "109",
        "217",
        "186",
        "91",
        "107",
        "125",
        "36",
        "156",
        "218",
        "30",
        "216",
        "218",
        "106",
        "127",
        "175",
        "95",
        "61",
        "174",
        "124",
        "200",
        "52",
        "72",
        "49",
        "29",
    ],
    [
        "93",
        "84",
        "194",
        "115",
        "24",
        "49",
        "132",
        "157",
        "151",
        "145",
        "154",
        "74",
        "41",
        "218",
        "82",
        "179",
        "24",
        "186",
        "45",
        "97",
        "111",
        "210",
        "100",
        "194",
        "119",
        "193",
        "214",
        "53",
        "27",
        "54",
    ],
    [
        "18",
        "178",
        "171",
        "228",
        "168",
        "157",
        "131",
        "150",
        "71",
        "222",
        "88",
        "220",
        "119",
        "187",
        "160",
        "151",
        "119",
        "94",
        "121",
        "204",
        "66",
        "88",
        "73",
        "115",
        "102",
        "115",
        "190",
        "200",
        "52",
        "75",
    ],
    [
        "162",
        "80",
        "116",
        "115",
        "211",
        "101",
        "78",
        "111",
        "50",
        "169",
        "85",
        "50",
        "216",
        "78",
        "183",
        "33",
        "220",
        "153",
        "228",
        "39",
        "131",
        "81",
        "99",
        "223",
        "227",
        "178",
        "54",
        "52",
        "38",
        "209",
    ],
    [
        "127",
        "42",
        "124",
        "106",
        "142",
        "190",
        "22",
        "232",
        "89",
        "217",
        "192",
        "213",
        "89",
        "96",
        "53",
        "113",
        "168",
        "119",
        "118",
        "59",
        "83",
        "184",
        "77",
        "112",
        "60",
        "179",
        "193",
        "170",
        "146",
        "148",
    ],
    [
        "105",
        "107",
        "86",
        "131",
        "140",
        "127",
        "64",
        "24",
        "230",
        "19",
        "100",
        "107",
        "112",
        "207",
        "214",
        "124",
        "128",
        "80",
        "202",
        "131",
        "180",
        "25",
        "209",
        "207",
        "110",
        "130",
        "68",
        "19",
        "231",
        "128",
    ],
    [
        "95",
        "75",
        "83",
        "179",
        "187",
        "94",
        "73",
        "200",
        "194",
        "224",
        "195",
        "226",
        "61",
        "168",
        "128",
        "65",
        "123",
        "92",
        "183",
        "160",
        "39",
        "227",
        "70",
        "37",
        "158",
        "221",
        "152",
        "90",
        "177",
        "224",
    ],
    [
        "215",
        "125",
        "189",
        "226",
        "30",
        "81",
        "198",
        "232",
        "17",
        "35",
        "37",
        "180",
        "116",
        "160",
        "113",
        "175",
        "29",
        "76",
        "33",
        "46",
        "175",
        "26",
        "178",
        "48",
        "66",
        "64",
        "30",
        "211",
        "123",
        "215",
    ],
    [
        "205",
        "178",
        "127",
        "123",
        "112",
        "209",
        "141",
        "19",
        "94",
        "218",
        "170",
        "71",
        "167",
        "59",
        "131",
        "191",
        "147",
        "52",
        "22",
        "194",
        "150",
        "26",
        "95",
        "34",
        "212",
        "102",
        "121",
        "66",
        "132",
        "29",
    ],
    [
        "189",
        "165",
        "224",
        "180",
        "133",
        "43",
        "204",
        "83",
        "78",
        "84",
        "99",
        "18",
        "212",
        "144",
        "120",
        "130",
        "112",
        "47",
        "103",
        "103",
        "97",
        "50",
        "143",
        "110",
        "96",
        "72",
        "83",
        "130",
        "111",
        "194",
    ],
    [
        "180",
        "96",
        "63",
        "91",
        "52",
        "229",
        "104",
        "17",
        "195",
        "213",
        "18",
        "74",
        "188",
        "74",
        "69",
        "210",
        "204",
        "183",
        "166",
        "71",
        "41",
        "159",
        "232",
        "141",
        "45",
        "135",
        "161",
        "197",
        "100",
        "228",
    ],
    [
        "77",
        "162",
        "92",
        "65",
        "51",
        "186",
        "68",
        "80",
        "184",
        "145",
        "217",
        "126",
        "103",
        "110",
        "24",
        "25",
        "48",
        "80",
        "74",
        "212",
        "88",
        "150",
        "186",
        "41",
        "48",
        "24",
        "194",
        "217",
        "96",
        "61",
    ],
    [
        "170",
        "119",
        "151",
        "80",
        "157",
        "77",
        "129",
        "183",
        "43",
        "162",
        "167",
        "226",
        "67",
        "77",
        "117",
        "132",
        "97",
        "150",
        "94",
        "84",
        "45",
        "66",
        "222",
        "47",
        "213",
        "117",
        "198",
        "119",
        "181",
        "72",
    ],
    [
        "20",
        "141",
        "142",
        "228",
        "169",
        "39",
        "151",
        "21",
        "117",
        "42",
        "42",
        "110",
        "175",
        "202",
        "232",
        "210",
        "129",
        "57",
        "78",
        "88",
        "227",
        "55",
        "76",
        "35",
        "223",
        "111",
        "96",
        "82",
        "47",
        "224",
    ],
    [
        "190",
        "134",
        "133",
        "193",
        "220",
        "174",
        "157",
        "200",
        "48",
        "231",
        "157",
        "226",
        "155",
        "128",
        "144",
        "231",
        "44",
        "73",
        "79",
        "211",
        "144",
        "29",
        "44",
        "45",
        "178",
        "213",
        "122",
        "96",
        "230",
        "90",
    ],
    [
        "73",
        "113",
        "117",
        "141",
        "22",
        "220",
        "135",
        "83",
        "185",
        "210",
        "26",
        "74",
        "67",
        "227",
        "139",
        "210",
        "232",
        "90",
        "192",
        "223",
        "194",
        "142",
        "117",
        "209",
        "184",
        "59",
        "219",
        "59",
        "145",
        "214",
    ],
    [
        "101",
        "216",
        "81",
        "212",
        "17",
        "194",
        "95",
        "137",
        "86",
        "207",
        "221",
        "144",
        "199",
        "45",
        "205",
        "127",
        "141",
        "97",
        "216",
        "121",
        "224",
        "136",
        "39",
        "142",
        "198",
        "102",
        "181",
        "218",
        "62",
        "61",
    ],
    [
        "134",
        "192",
        "73",
        "39",
        "169",
        "126",
        "80",
        "19",
        "191",
        "184",
        "221",
        "141",
        "172",
        "224",
        "183",
        "219",
        "21",
        "181",
        "45",
        "191",
        "132",
        "171",
        "203",
        "155",
        "57",
        "141",
        "98",
        "36",
        "61",
        "63",
    ],
    [
        "68",
        "174",
        "172",
        "192",
        "138",
        "84",
        "137",
        "175",
        "109",
        "88",
        "103",
        "162",
        "69",
        "155",
        "183",
        "20",
        "93",
        "77",
        "85",
        "63",
        "191",
        "18",
        "93",
        "61",
        "38",
        "213",
        "34",
        "56",
        "86",
        "55",
    ],
    [
        "114",
        "203",
        "194",
        "25",
        "94",
        "97",
        "51",
        "33",
        "199",
        "170",
        "57",
        "163",
        "215",
        "128",
        "27",
        "153",
        "105",
        "211",
        "168",
        "232",
        "28",
        "146",
        "193",
        "70",
        "180",
        "61",
        "54",
        "166",
        "188",
        "42",
    ],
    [
        "199",
        "232",
        "138",
        "74",
        "187",
        "211",
        "111",
        "133",
        "138",
        "37",
        "221",
        "137",
        "39",
        "66",
        "48",
        "214",
        "208",
        "209",
        "115",
        "117",
        "202",
        "120",
        "24",
        "189",
        "137",
        "151",
        "170",
        "222",
        "56",
        "117",
    ],
    [
        "58",
        "194",
        "165",
        "191",
        "36",
        "171",
        "182",
        "127",
        "215",
        "207",
        "115",
        "124",
        "28",
        "122",
        "147",
        "99",
        "98",
        "203",
        "23",
        "27",
        "107",
        "138",
        "207",
        "122",
        "181",
        "161",
        "53",
        "62",
        "52",
        "35",
    ],
]


class SizedTerminal(Terminal):
    """A terminal class with a pre-determined size."""

    def _get_size(self) -> tuple[int, int]:
        return (80, 25)


def _generate_stressor(term: Terminal = terminal) -> Recorder:
    pytermgui.set_global_terminal(term)

    with term.record() as recording:
        width, height = 30, 30
        matrix = DensePixelMatrix(width, height)

        for y, row in enumerate(MATRIX):
            for x, char in enumerate(row):
                matrix[y, x] = char
        matrix.build()

        for line in matrix.get_lines():
            term.print(line)

        tim.print("[@141 61]Hello[inverse]There")

    return recording


def _diff(output: str, expected: str) -> tuple[str, str]:
    red = str_to_color("red")

    buff = ""
    count = 0
    for o, e in zip(output, expected):
        if o != e:
            buff += red(o)
            count += 1
        else:
            buff += o

    return buff, red(str(count))


def test_export_html():
    recording = _generate_stressor()

    Color.default_background = str_to_color("#000000")
    Color.default_foreground = str_to_color("#ffffff")

    output = recording.export_html()

    if output != HTML_TARGET:
        print(*_diff(output, HTML_TARGET))

    compare(output, HTML_TARGET)


def test_export_svg():
    terminal = SizedTerminal()

    recording = _generate_stressor(terminal)

    Color.default_background = str_to_color("#000000")
    Color.default_foreground = str_to_color("#ffffff")

    output = recording.export_svg()

    if output != SVG_TARGET:
        print(*_diff(output, SVG_TARGET))

    compare(output, SVG_TARGET)


def regenerate_targets():
    Color.default_background = str_to_color("#000000")
    Color.default_foreground = str_to_color("#ffffff")

    html_target = _generate_stressor().export_html()
    svg_target = _generate_stressor(SizedTerminal()).export_svg()

    with open("tests/_exporter_targets.py", "w") as f:
        f.write(f'SVG_TARGET = """\\\n{svg_target}"""\n\n')
        f.write(f'HTML_TARGET = """\\\n{html_target}"""\n')


if __name__ == "__main__":
    regenerate_targets()
